/**
 * 
 */
package good_src.Strategy;

import java.util.Collection;
import java.util.Stack;

import good_src.Implementation.ConcreteCapteur;
import good_src.Implementation.Epoque;
import good_src.Interfaces.Algorithme;
import good_src.Interfaces.ObservateurCapteur;
import good_src.Interfaces.Subject;

/**
 * @author Tangi Midy & Fabien Le Peih
 * The Versionned Strategy consists in attributing a value to a version
 * <p>When a requester demands an update, it receives the current version, so the current value of the 
 * capteur.</ br> Therefore, every displayers won't have the same version at the same time</p>
 */
public class EpoqueStrategy implements Algorithme {

	private Subject<Integer> capteur; // The initial subject
	private Stack<Epoque> versions; // a Stack of value-version
	private int version=0;


	private Epoque epoque; // the object that attributes version and value to the stack
	private VerifCanaux verifCanaux;
	private Thread t;
	
	/**
	 * Constructor of the class
	 */
	public EpoqueStrategy(Subject<Integer> capteur) {
		this.capteur=capteur;
		verifCanaux = new VerifCanaux(((ConcreteCapteur) capteur).getObservers());
	}

	/** 
	 * @see good_src.Interfaces.Algorithme#configure()
	 */
	@Override
	public void configure() {
		versions = new Stack<Epoque>();
	}
	
	/** 
	 * @see good_src.Interfaces.Algorithme#execute()
	 */
	@Override
	public void execute() {
		//We create a new epoque when a new version is available
		epoque= new Epoque(version+1,capteur.getValue());
		versions.push(epoque);

		//Increment Version
		version++;

		t = new Thread(verifCanaux, "Thread" + capteur.getValue());
		t.start();
	}
	
	/**
	 * Methods used to retrieve the value at the specified version
	 * @param idVersion the version ident
	 * @return  the version's value
	 */
	public int getvalueAt(int idVersion){
		Epoque e = versions.firstElement();
		
		while(versions.elements().hasMoreElements()){
			if (e.getVersion()==idVersion){
				return e.getValue();
			}
			e=versions.elements().nextElement();
		}
		
		return -1;
	}
	
	/**
	 * 
	 * @return the current version
	 */
	public int getVersion() {
		return version;
	}
	
	public String toString(){
		System.out.println("Liste des Doublet Versions-Valeurs du capteur");
		int cpt=1;
		String res="[";
		for (Object e : versions.toArray()){
			res=res+ "("+((Epoque)e).getVersion()+","+((Epoque)e).getValue()+")";
			if (cpt==10){
				res=res+"\n";
				cpt=0;
			}
			cpt++;
		}
		res=res+ "]";
		return res;
	}
	
	/***************************************Intern Class***********************************************/
	
	
	/**
	 * This intern class is contained in a Thread loaded at
	 * each update of the value
	 * It checks the streams and see if they're able to be updated
	 */
	private class VerifCanaux implements Runnable{
		
		private int value; // The current value
		private Collection<ObservateurCapteur> canaux;
		
		public VerifCanaux(Collection<ObservateurCapteur> canaux){
			this.canaux=canaux;
		}

		/**
		 * 
		 * @see java.lang.Runnable#run()
		 */
		@Override
		public void run() {
			for (ObservateurCapteur c : canaux) {
				//We check the availability of every stream
				if (c.isUpdatable()){
					c.update();
				}
			}
		}

		public int getValue() {
			return value;
		}

		public void setValue(int value) {
			this.value = value;
		}

		public Collection<ObservateurCapteur> getCanaux() {
			return canaux;
		}

		public void setCanaux(Collection<ObservateurCapteur> canaux) {
			this.canaux = canaux;
		}
		
	}
	
	
	
}
